////////////////////////////////////////////////////////////////////////////
//
//  Crytek Engine Source File.
//  Copyright (C), Crytek Studios, 2010.
// -------------------------------------------------------------------------
//  Version:     v1.00
//  Created:     Michael Kopietz
//  Description: unified vector math lib
// -------------------------------------------------------------------------
//  History:		- created 1999  for Katmai and K3
//							-	...
//							-	integrated into cryengine
//
////////////////////////////////////////////////////////////////////////////
#ifndef __D_VMATH_XENON__
#define __D_VMATH_XENON__


typedef __vector4 vec4;


#include "VMath_Prototypes.hpp"

#define SWIZZLEMASK5(X,Y,Z,W)	((X)|(Y<<2)|(Z<<4)|(W<<6))
#define SWIZZLEMASK4(N,X,Y,Z)	N##x	=	SWIZZLEMASK5(X,Y,Z,0),\
															N##y	=	SWIZZLEMASK5(X,Y,Z,1),\
															N##z	=	SWIZZLEMASK5(X,Y,Z,2),\
															N##w	=	SWIZZLEMASK5(X,Y,Z,3),
#define SWIZZLEMASK3(N,X,Y)		SWIZZLEMASK4(N##x,X,Y,0)\
															SWIZZLEMASK4(N##y,X,Y,1)\
															SWIZZLEMASK4(N##z,X,Y,2)\
															SWIZZLEMASK4(N##w,X,Y,3)
#define SWIZZLEMASK2(N,X)			SWIZZLEMASK3(N##x,X,0)\
															SWIZZLEMASK3(N##y,X,1)\
															SWIZZLEMASK3(N##z,X,2)\
															SWIZZLEMASK3(N##w,X,3)
#define SWIZZLEMASK1					SWIZZLEMASK2(x,0)\
															SWIZZLEMASK2(y,1)\
															SWIZZLEMASK2(z,2)\
															SWIZZLEMASK2(w,3)

enum ESwizzleMask
{
	SWIZZLEMASK1
};

enum ECacheLvl
{
	ECL_LVL1,
	ECL_LVL2,
	ECL_LVL3,
};
#define OldBitX	1
#define OldBitY	2
#define OldBitZ	4
#define OldBitW	8
#define BitX	0x00000080
#define BitY	0x00008000
#define BitZ	0x00800000
#define BitW	0x80000000

	ILINE vec4				Vec4(float x,float y,float z,float w)
										{
											__vector4 V={x,y,z,w};
											return V;
										}
	ILINE vec4				Vec4(uint32 x,uint32 y,uint32 z,uint32 w)
										{
											__vector4i V={x,y,z,w};
											return *reinterpret_cast<__vector4*>(&V);
										}
	ILINE vec4				Vec4(float x)
										{
											vec4 V=__lvlx(&x,0);
											return __vspltw(V,0);
										}
	ILINE int32				Vec4int32(vec4 V,uint32 Idx)
										{
											//DWORD Ret _ALIGN(16);
											//__stvewx(__vspltw(V,Idx),&Ret,0);
											//return Ret;
											return V.u[Idx];
										}
	ILINE vec4				Vec4Zero()
										{
											return  __vspltisw(0);
										}

	ILINE vec4				Vec4One()
										{
											static const __vector4 V={1.f,1.f,1.f,1.f};
											return V;	
										}
	ILINE vec4				Vec4Four()
										{
											__vector4 V={4.f,4.f,4.f,4.f};
											return V;	
										}
	ILINE vec4				Vec4ZeroOneTwoThree()
										{
											__vector4 V={0.f,1.f,2.f,3.f};
											return V;	
										}
	ILINE vec4				Vec4FFFFFFFF()
										{
											return __vspltisw(-1);
										}
	ILINE vec4				Vec4Epsilon()
										{
											__vector4 V={FLT_EPSILON,FLT_EPSILON,FLT_EPSILON,FLT_EPSILON};
											return V;	
										}

	template<ECacheLvl L>
	ILINE void				Prefetch(const void* pData)
										{
											__dcbt(0,pData);
										}
	template<ESwizzleMask M>
	ILINE vec4				Shuffle(vec4 V0,vec4 V1)
										{
											static const XMVECTORU8 MASK = { (M&3)*4,(M&3)*4+1,(M&3)*4+2,(M&3)*4+3,
																										((M>>2)&3)*4,((M>>2)&3)*4+1,((M>>2)&3)*4+2,((M>>2)&3)*4+3,
																										((M>>4)&3)*4+16,((M>>4)&3)*4+17,((M>>4)&3)*4+18,((M>>4)&3)*4+19,
																										((M>>6)&3)*4+16,((M>>6)&3)*4+17,((M>>6)&3)*4+18,((M>>6)&3)*4+19};
											return __vperm(V0,V1,MASK);
											//return Vec4(V0.u[M&3],V0.u[(M>>2)&3],V1.u[(M>>4)&3],V1.u[(M>>6)&3]);
										}
	template<ESwizzleMask M>
	ILINE vec4				Swizzle(vec4 V)
										{
											const uint32 X = M&3, Y = (M>>2)&3, Z = (M>>4)&3, W = (M>>6)&3;
											return __vpermwi( V, (X << 6) | (Y << 4) | (Z << 2) | W );
										}
	ILINE vec4				Add(vec4 V0,vec4 V1)
										{
											return __vaddfp(V0,V1);
										}
	ILINE vec4				Sub(vec4 V0,vec4 V1)
										{
											return __vsubfp(V0,V1);
										}
	ILINE vec4				Mul(vec4 V0,vec4 V1)
										{
											return __vmulfp(V0,V1);
										}
	ILINE vec4				Div(vec4 V0,vec4 V1)
										{
											return Mul(V0,Rcp(V1));
										}
	ILINE vec4				RcpFAST(vec4 V)
										{
											return __vrefp(V);
										}
	ILINE vec4				DivFAST(vec4 V0,vec4 V1)
										{
											return Mul(V0,RcpFAST(V1));
										}
	ILINE vec4				Rcp(vec4 V)
										{
											vec4 R = RcpFAST(V);
											return Madd(R,__vnmsubfp(R,V,Vec4One()),R);
										}
	ILINE vec4				Madd(vec4 V0,vec4 V1,vec4 V2)
										{
											return __vmaddfp(V0,V1,V2);
										}
	ILINE vec4				Msub(vec4 V0,vec4 V1,vec4 V2)
										{
											return Sub(Mul(V0,V1),V2);
										}
	ILINE vec4				Min(vec4 V0,vec4 V1)
										{
											return __vminfp(V0,V1);
										}
	ILINE vec4				Max(vec4 V0,vec4 V1)
										{
											return __vmaxfp(V0,V1);
										}
	ILINE vec4				floatToint32(vec4 V)
										{
											return __vctsxs(V,0);
										}
	ILINE vec4				int32Tofloat(vec4 V)
										{
											return __vcfsx(V,0);
										}
	ILINE vec4				CmpLE(vec4 V0,vec4 V1)
										{
											return __vcmpgefp(V1,V0);
										}
	ILINE uint32			SignMask(vec4 V)
										{
											const	XMVECTORU8 MASK			=	{	12,8,4,0,
																										0,0,0,0,
																										0,0,0,0,
																										0,0,0,0};
											return Vec4int32(__vperm(V,V,*reinterpret_cast<const __vector4*>(&MASK)),0)&(BitX|BitY|BitZ|BitW);
											//return (V.u[0]>>31)|((V.u[1]>>31)<<1)|((V.u[2]>>31)<<2)|((V.u[3]>>31)<<3);
										}
	ILINE vec4				And(vec4 V0,vec4 V1)
										{
											return __vand(V0,V1);
										}
	ILINE vec4				AndNot(vec4 V0,vec4 V1)
										{
											return __vandc(V0,V1);
										}
	ILINE vec4				Or(vec4 V0,vec4 V1)
										{
											return __vor(V0,V1);
										}
	ILINE vec4				Xor(vec4 V0,vec4 V1)
										{
											return __vxor(V0,V1);
										}
	ILINE vec4				Select(vec4 V0,vec4 V1,vec4 M)
										{
											return SelectSign(V0,V1,M);
										}
	ILINE vec4				SelectSign(vec4 V0,vec4 V1,vec4 M)
										{
											static const XMVECTORI V31 = {31,31,31,31};
											return __vsel(V0,V1,__vsraw(M,V31));
										}

#endif

